package com.sinosoft.dsp.platform.services;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.NoneScoped;
import javax.faces.model.SelectItem;

import org.primefaces.model.DefaultTreeNode;

import com.sinosoft.builder.templates.concept.BusinessConcept;
import com.sinosoft.builder.templates.concept.CodeHierarchyStructure;
import com.sinosoft.builder.templates.concept.CodeSet;
import com.sinosoft.builder.templates.concept.CodeType;
import com.sinosoft.builder.templates.concept.NamingElement;
import com.sinosoft.dsp.persistence.businessconcept.facade.CodeFacade;
import com.sinosoft.dsp.persistence.businessconcept.facade.ICodeFacade;
import com.sinosoft.dsp.platform.components.portal.iteration.ISinoTreeDataObject;
import com.sinosoft.dsp.platform.components.portal.iteration.SinoTreeDataObject;
import com.sinosoft.dsp.platform.exception.SinoPlatformException;
import com.sinosoft.dsp.platform.manager.ApplicationBuilder;
import com.sinosoft.dsp.platform.utils.SinoManagedBean;
import com.sinosoft.dsp.system.core.log.Log;
import com.sinosoft.dsp.system.utils.Const;

/**
 * 代码集服务类
 * 
 * @author 潘巍（PeterPan）
 * @since 2011-6-26 下午09:26:22
 * 
 */
@ManagedBean(name = "codeSetService")
@NoneScoped
public class CodeSetService {

	private static final Log log = Log.getLog(CodeSetService.class.getName());

	/**
	 * 通过id获得代码集对象
	 * 
	 * @param encode
	 * @return
	 */
	public CodeSet getCodeSetById(String id) {
		try {
			ApplicationBuilder ab = SinoManagedBean
					.findBean("applicationBuilder");
			if (ab.getCodeSets() == null) {
				initCodeSet();
			}
			return ab.getCodeSets().get(id);
		} catch (Exception e) {
			log.error("通过id获得代码集对象出现错误(getCodeSetById)！");
		}
		return null;
	}

	/**
	 * 通过ID获得代码集的ID和ICodeFacade的对应Map
	 * 
	 * @param id
	 * @return
	 */
	public Map<String, ICodeFacade> getCodeSetTrees(String id) {
		try {
			ApplicationBuilder ab = SinoManagedBean
					.findBean("applicationBuilder");
			if (ab.getCodeSetTrees() == null
					|| ab.getCodeSetTrees().get(id) == null) {
				initCodeSetTrees(id);
			}
			return ab.getCodeSetTrees().get(id);
		} catch (Exception e) {
			log.error("通过ID获得代码集的ID和ICodeFacade的对应Map出现错误(getCodeSetTrees)！");
		}
		return null;
	}

	/**
	 * 通过ID获得代码集的命名
	 * 
	 * @param id
	 * @return
	 */
	public NamingElement getCodeSetNamingElement(String id) {
		try {

			ApplicationBuilder ab = SinoManagedBean
					.findBean("applicationBuilder");
			if (ab.getCodeSetTrees() == null
					|| ab.getCodeSetTrees().get(id) == null) {
				initCodeSetTrees(id);
			}
			CodeSet cs = ab.getCodeSets().get(id);

			List<NamingElement> nes = cs.getNamingElement();
			return nes.get(nes.size() - 1);

		} catch (Exception e) {
			log.error("通过ID获得代码集的命名出现错误(getCodeSetNamingElement)！");
		}
		return null;
	}

	/**
	 * 通过ID获得代码集的命名
	 * 
	 * @param id
	 * @param date
	 * @return
	 */
	public NamingElement getCodeSetNamingElement(String id, Calendar date) {
		try {
			if (date == null) {
				return getCodeSetNamingElement(id);
			}
			ApplicationBuilder ab = SinoManagedBean
					.findBean("applicationBuilder");
			if (ab.getCodeSetTrees() == null
					|| ab.getCodeSetTrees().get(id) == null) {
				initCodeSetTrees(id);
			}
			CodeSet cs = ab.getCodeSets().get(id);

			List<NamingElement> nes = cs.getNamingElement();
			int index = 0;
			for (NamingElement ne : nes) {
				if (ne.getChangedTime().toGregorianCalendar().compareTo(date) > 0)
					break;
				else
					index++;
			}
			index--;
			if (index > -1) {
				return nes.get(index);
			}
			return null;

		} catch (Exception e) {
			log.error("通过ID获得代码集的命名出现出现错误(getCodeSetNamingElement)！");
		}
		return null;
	}

	/**
	 * 初始化代码集对象
	 */
	private void initCodeSet() {
		ApplicationBuilder ab = SinoManagedBean.findBean("applicationBuilder");
		Map<String, CodeSet> codeSets = new HashMap<String, CodeSet>();
		BusinessConcept bc = ab.getConcept();
		if (bc.getDictionaryCodingConcept().getCodeSet() != null) {
			for (CodeSet cs : bc.getDictionaryCodingConcept().getCodeSet()) {
				codeSets.put(cs.getId(), cs);
			}
		}
		ab.setCodeSets(codeSets);
	}

	/**
	 * 初始化代码集树
	 * 
	 * @param id
	 */
	private void initCodeSetTrees(String id) {
		ApplicationBuilder ab = SinoManagedBean.findBean("applicationBuilder");
		if (ab.getCodeSetTrees() == null) {
			ab.setCodeSetTrees(new HashMap<String, Map<String, ICodeFacade>>());
		}
		CodeSet cs = getCodeSetById(id);
		if (cs != null) {
			Map<String, ICodeFacade> nodes = new HashMap<String, ICodeFacade>();
			// 初始化所有代码节点
			if (cs.getCode() != null) {
				for (CodeType ct : cs.getCode()) {
					ICodeFacade csf = new CodeFacade(ct);
					nodes.put(csf.getId(), csf);
				}
			}
			ab.getCodeSetTrees().put(id, nodes);
		}
	}

	/**
	 * 判断层次结构是否在指定时间上有效
	 * 
	 * @param chs
	 *            层次结构
	 * @param c
	 *            指定时间
	 * @return
	 */
	private boolean checkValidCodeHierarchyStructure(
			CodeHierarchyStructure chs, Calendar c) {
		if (c == null) {
			c = Calendar.getInstance();
		}
		if (chs.getCreateTime().toGregorianCalendar().compareTo(c) <= 0) {
			if (chs.getEndTime() != null
					&& chs.getEndTime().toGregorianCalendar().compareTo(c) <= 0) {
				return false;
			}
			return true;
		}
		return false;
	}

	/**
	 * 通过id获得树形代码表
	 * 
	 * @param id
	 *            代码表ID
	 * @return Object[] 第一元素是根节点，第二元素是节点和ID的映射
	 * @throws SinoPlatformException
	 */
	public Object[] getCodeSetTreeById(String id) throws SinoPlatformException {
		return getCodeSetTreeById(id, null);
	}

	private void setDataForNode(DefaultTreeNode node, ISinoTreeDataObject data) {
		setDataForNode(node, data, null);
	}

	private void setDataForNode(DefaultTreeNode node, ISinoTreeDataObject data,
			String defaultType) {
		node.setData(data);
		if (data != null && !Const.isEmpty(data.getType())) {
			node.setType(data.getType());
		} else {
			node.setType(defaultType);
		}
	}

	/**
	 * 通过id获得树形代码表
	 * 
	 * @param id
	 *            代码表ID
	 * @param c
	 *            指定时间
	 * @return Object[] 第一元素是根节点，第二元素是ID和具体节点的映射 第一个元素类型：TreeNode<ICodeFacade> <br>
	 *         第二个元素类型：Map<String, TreeNode<ICodeFacade>>
	 * @throws SinoPlatformException
	 */
	public Object[] getCodeSetTreeById(String id, Calendar c)
			throws SinoPlatformException {
		try {
			Calendar c2 = c;
			if (c2 == null) {
				c2 = Calendar.getInstance();
			}
			// 构建父子结构，获得根节点
			CodeSet cs = getCodeSetById(id);
			Map<String, ICodeFacade> csTree = getCodeSetTrees(id);
			// 根节点
			DefaultTreeNode root = new DefaultTreeNode();
			ISinoTreeDataObject rootDo = new SinoTreeDataObject();
			NamingElement rootNe = getCodeSetNamingElement(id, c);
			rootDo.setId(cs.getId());
			rootDo
					.setName((Const.isEmpty(rootNe.getAbbreviationName())) ? rootNe
							.getFullName()
							: rootNe.getAbbreviationName());
			rootDo.setAlt(rootNe.getFullName());
			rootDo.setType(ISinoTreeDataObject.TREE_TYPE_NODE);
			setDataForNode(root, rootDo);
			// 节点和ID的映射
			Map<String, DefaultTreeNode> nodes = new HashMap<String, DefaultTreeNode>();
			nodes.put(cs.getId(), root);
			// 创建树节点
			Map<String, String> parentIds = new HashMap<String, String>();
			if (cs.getCodeHierarchyStructure() != null) {
				for (CodeHierarchyStructure chs : cs
						.getCodeHierarchyStructure()) {
					if (checkValidCodeHierarchyStructure(chs, c2)) {
						String pNodeId = chs.getParentNode().getId();
						String sNodeId = chs.getSubNode().getId();
						if (!parentIds.containsKey(pNodeId))
							parentIds.put(pNodeId, "p");
						parentIds.put(sNodeId, "s");
						DefaultTreeNode ptn = nodes.get(pNodeId);
						if (ptn == null) {
							ptn = new DefaultTreeNode();
							ISinoTreeDataObject ptdo = csTree.get(pNodeId)
									.createTreeDataObject(c);
							setDataForNode(ptn, ptdo,
									ISinoTreeDataObject.TREE_TYPE_NODE);
							nodes.put(pNodeId, ptn);
						} else {
							if (Const.isEmpty(ptn.getType())) {
								ptn.setType(ISinoTreeDataObject.TREE_TYPE_NODE);
							}
							ISinoTreeDataObject ptdo = (ISinoTreeDataObject) ptn
									.getData();
							if (Const.isEmpty(ptdo.getType())) {
								ptdo
										.setType(ISinoTreeDataObject.TREE_TYPE_NODE);
							}
						}

						DefaultTreeNode stn = nodes.get(sNodeId);
						if (stn == null) {
							stn = new DefaultTreeNode();
							ISinoTreeDataObject stdo = csTree.get(sNodeId)
									.createTreeDataObject(c);
							stdo.setParentId(pNodeId);
							setDataForNode(stn, stdo,
									ISinoTreeDataObject.TREE_TYPE_LEAF);
							nodes.put(sNodeId, stn);
						} else {
							((ISinoTreeDataObject) stn.getData())
									.setParentId(pNodeId);
						}

						ptn.addChild(stn);
					}
				}
			}

			// 给父节点设置其父节点为root
			Object[] pids = parentIds.keySet().toArray();
			if (pids != null) {
				for (Object pid : pids) {
					if ("p".equals(parentIds.get(pid))) {
						root.addChild(nodes.get(pid));
						((ISinoTreeDataObject) nodes.get(pid).getData())
								.setParentId(cs.getId());
					}
				}
			}

			// 将没有出现在继承关系中出现的节点设置其父节点为root
			if (cs.getCode() != null) {
				for (CodeType ct : cs.getCode()) {
					String ctid = ct.getId();
					ICodeFacade ctf = csTree.get(ctid);
					if (!nodes.containsKey(ctid) && ctf.isValid(c2)) {
						DefaultTreeNode tn = new DefaultTreeNode();
						ISinoTreeDataObject tdo = ctf.createTreeDataObject(c);
						tdo.setParentId(cs.getId());
						tn.setData(tdo);
						setDataForNode(tn, tdo,
								ISinoTreeDataObject.TREE_TYPE_LEAF);
						nodes.put(ctid, tn);

						root.addChild(tn);
					}
				}
			}

			return new Object[] { root, nodes };
		} catch (Exception e) {
			log.error("通过id获得树形代码表出现错误(getCodeSetTreeById)！");
			throw new SinoPlatformException("通过id获得树形代码表出现错误！", e);
		}
	}

	/**
	 * 获得首层的代码树
	 * 
	 * @param id
	 * @return
	 */
	public List<SinoTreeDataObject> getRootSubCodesTree(String id) {
		return getRootSubCodesTree(id, null);
	}

	/**
	 * 获得首层的代码树
	 * 
	 * @param id
	 * @param c
	 * @return
	 */
	public List<SinoTreeDataObject> getRootSubCodesTree(String id, Calendar c) {
		List<SinoTreeDataObject> nodes = new ArrayList<SinoTreeDataObject>();
		List<ICodeFacade> sub = getRootSubCodes(id, c);
		if (sub != null) {
			for (ICodeFacade cf : sub) {
				SinoTreeDataObject tdo = (SinoTreeDataObject) cf
						.createTreeDataObject(c);
				tdo.setType(ISinoTreeDataObject.TREE_TYPE_NODE);
				nodes.add(tdo);
			}
		}
		return nodes;
	}

	/**
	 * 获得根节点的直接子节点的SelectItem集合<br>
	 * SelectItem的value是ICodeFacade类型的对象
	 * 
	 * @param id
	 * @return
	 */
	public List<SelectItem> getRootSubCodesSelectItems(String id) {
		return getRootSubCodesSelectItems(id, null);
	}

	/**
	 * 获得根节点的直接子节点的SelectItem集合<br>
	 * SelectItem的value是ICodeFacade类型的对象
	 * 
	 * @param id
	 * @param c
	 * @return
	 */
	public List<SelectItem> getRootSubCodesSelectItems(String id, Calendar c) {
		List<SelectItem> sis = new ArrayList<SelectItem>();
		List<ICodeFacade> sub = getRootSubCodes(id, c);
		if (sub != null) {
			for (ICodeFacade cf : sub) {
				sis.add(new SelectItem(cf, cf.getName(c)));
			}
		}
		return sis;
	}

	public List<SelectItem> getRootSubCodesSelectItems2(String id) {
		return getRootSubCodesSelectItems2(id, null);
	}

	public List<SelectItem> getRootSubCodesSelectItems2(String id, Calendar c) {
		List<SelectItem> sis = new ArrayList<SelectItem>();
		List<ICodeFacade> sub = getRootSubCodes(id, c);
		if (sub != null) {
			for (ICodeFacade cf : sub) {
				sis.add(new SelectItem(cf.getId(), cf.getName(c)));
			}
		}
		return sis;
	}

	/**
	 * 获得代码表的直接子节点
	 * 
	 * @param id
	 *            代码类型ID
	 * @return
	 */
	public List<ICodeFacade> getRootSubCodes(String id) {
		return getRootSubCodes(id, null);
	}

	/**
	 * 获得代码表的直接子节点
	 * 
	 * @param id
	 *            代码类型ID
	 * @param c
	 *            指定时间
	 * @return
	 */
	public List<ICodeFacade> getRootSubCodes(String id, Calendar c) {
		try {
			Calendar c2 = c;
			if (c2 == null) {
				c2 = Calendar.getInstance();
			}
			// 构建父子结构，获得根节点
			CodeSet cs = getCodeSetById(id);
			Map<String, ICodeFacade> csTree = getCodeSetTrees(id);

			Map<String, String> valid = new HashMap<String, String>();

			// 获得有效代码
			if (csTree != null) {
				for (Iterator<Map.Entry<String, ICodeFacade>> iter = csTree
						.entrySet().iterator(); iter.hasNext();) {
					Map.Entry<String, ICodeFacade> entry = iter.next();
					if (entry.getValue().isValid(c)) {
						valid.put(entry.getKey(), null);
					}
				}
			}

			// 删除子节点
			if (cs.getCodeHierarchyStructure() != null) {
				for (CodeHierarchyStructure chs : cs
						.getCodeHierarchyStructure()) {
					if (checkValidCodeHierarchyStructure(chs, c2)) {
						valid.remove(chs.getSubNode().getId());
					}
				}
			}

			// 创建子节点
			List<ICodeFacade> rtn = new ArrayList<ICodeFacade>();
			for (String key : valid.keySet()) {
				rtn.add(csTree.get(key));
			}

			return rtn;
		} catch (Exception e) {
			log.error("获得代码表的直接子节点出现错误(getRootSubCodes)！");
		}
		return null;
	}

	/**
	 * 获得指定父节点的子节点树Node
	 * 
	 * @param id
	 * @param pId
	 * @return
	 */
	public List<SinoTreeDataObject> getSubCodesTree(String id, String pId) {
		return getSubCodesTree(id, pId, null);
	}

	/**
	 * 获得指定父节点的子节点树Node
	 * 
	 * @param id
	 * @param pId
	 * @param c
	 * @return
	 */
	public List<SinoTreeDataObject> getSubCodesTree(String id, String pId,
			Calendar c) {
		try {
			List<SinoTreeDataObject> nodeList = new ArrayList<SinoTreeDataObject>();
			List<ICodeFacade> sub = getSubCodes(id, pId, c);
			if (sub != null) {
				for (ICodeFacade cf : sub) {
					SinoTreeDataObject tdo = (SinoTreeDataObject) cf
							.createTreeDataObject(c);
					tdo.setType(ISinoTreeDataObject.TREE_TYPE_LEAF);
					tdo.setParentId(pId);
					nodeList.add(tdo);
				}
			}
			return nodeList;
		} catch (Exception e) {
			log.error("获得指定父节点的子节点树Node出现错误(getSubCodesTree)！");
		}
		return null;
	}

	/**
	 * 获得指定父节点的子节点SelectItem集合<br>
	 * SelectItem的value是ICodeFacade类型的对象
	 * 
	 * @param id
	 * @param pId
	 * @return
	 */
	public List<SelectItem> getSubCodesSelectItems(String id, String pId) {
		return getSubCodesSelectItems(id, pId, null);
	}

	/**
	 * 获得指定父节点的子节点SelectItem集合<br>
	 * SelectItem的value是ICodeFacade类型的对象
	 * 
	 * @param id
	 * @param pId
	 * @param c
	 * @return
	 */
	public List<SelectItem> getSubCodesSelectItems(String id, String pId,
			Calendar c) {
		List<SelectItem> sis = new ArrayList<SelectItem>();
		List<ICodeFacade> sub = getSubCodes(id, pId, c);
		if (sub != null) {
			for (ICodeFacade cf : sub) {
				new SelectItem(cf, cf.getName(c));
			}
		}
		return sis;
	}

	public List<SelectItem> getSubCodesSelectItems2(String id, String pId) {
		return getSubCodesSelectItems2(id, pId, null);
	}

	public List<SelectItem> getSubCodesSelectItems2(String id, String pId,
			Calendar c) {
		List<SelectItem> sis = new ArrayList<SelectItem>();
		List<ICodeFacade> sub = getSubCodes(id, pId, c);
		if (sub != null) {
			for (ICodeFacade cf : sub) {
				new SelectItem(cf.getId(), cf.getName(c));
			}
		}
		return sis;
	}

	/**
	 * 获得指定节点的所有直接子节点
	 * 
	 * @param id
	 *            代码类型ID
	 * @param pId
	 *            父节点ID
	 * @return
	 */
	public List<ICodeFacade> getSubCodes(String id, String pId) {
		return getSubCodes(id, pId, null);
	}

	/**
	 * 获得指定节点的所有直接子节点
	 * 
	 * @param id
	 *            代码类型ID
	 * @param pId
	 *            父节点ID
	 * @param c
	 *            指定时间
	 * @return
	 */
	public List<ICodeFacade> getSubCodes(String id, String pId, Calendar c) {
		try {
			Calendar c2 = c;
			if (c2 == null) {
				c2 = Calendar.getInstance();
			}

			CodeSet cs = getCodeSetById(id);
			Map<String, ICodeFacade> csTree = getCodeSetTrees(id);

			List<ICodeFacade> rtn = new ArrayList<ICodeFacade>();

			if (cs.getCodeHierarchyStructure() != null) {
				for (CodeHierarchyStructure chs : cs
						.getCodeHierarchyStructure()) {
					if (checkValidCodeHierarchyStructure(chs, c2)
							&& chs.getParentNode().getId().equals(pId)) {
						rtn.add(csTree.get(chs.getSubNode().getId()));
					}
				}
			}

			return rtn;
		} catch (Exception e) {
			log.error("获得指定节点的所有直接子节点出现错误(getSubCodes)！");
		}
		return null;
	}

	/**
	 * 通过代码表ID和具体代码ID获得代码对象
	 * 
	 * @param id
	 * @param csId
	 * @return
	 */
	public ICodeFacade getCode(String id, String csId) {
		try {
			Map<String, ICodeFacade> csTree = getCodeSetTrees(id);
			if (csTree != null)
				return csTree.get(csId);
		} catch (Exception e) {
			log.error("通过代码表ID和具体代码ID获得代码对象出现错误(getCode)！");
		}
		return null;
	}

	/**
	 * 通过代码表ID和具体代码ID获得代码名称
	 * 
	 * @param id
	 * @param csId
	 * @return
	 */
	public String getCodeName(String id, String csId) {
		ICodeFacade code = getCode(id, csId);
		if (code != null) {
			return code.getName();
		}
		return csId;
	}

	/**
	 * 通过代码表ID和具体代码值获得代码对象
	 * 
	 * @param id
	 * @param value
	 * @return
	 */
	public ICodeFacade getCodeByValue(String id, String value) {
		try {
			Map<String, ICodeFacade> csTree = getCodeSetTrees(id);
			if (csTree != null) {
				for (ICodeFacade code : csTree.values()) {
					if (value.equals(code.getValue())) {
						return code;
					}
				}
			}
		} catch (Exception e) {
			log.error("通过代码表ID和具体代码值获得代码对象出现错误(getCodeByValue)！");
		}
		return null;
	}

	/**
	 * 通过代码表ID和具体代码值获得代码对象
	 * 
	 * @param id
	 * @param value
	 * @return
	 */
	public String getCodeNameByValue(String id, String value) {
		ICodeFacade code = getCodeByValue(id, value);
		if (code != null) {
			return code.getName();
		}
		return value;
	}

	/**
	 * 刷新代码集
	 * 
	 * @param codeset
	 */
	public void flushCodeSet(CodeSet codeset) {
		flushCodeSet("update", codeset);
	}

	/**
	 * 刷新代码集
	 * 
	 * @param type
	 * @param codeset
	 */
	public void flushCodeSet(String type, CodeSet codeset) {
		try {
			ApplicationBuilder ab = SinoManagedBean
					.findBean("applicationBuilder");
			// 更新业务概念中的对应代码集
			if (ab.getConcept() != null) {
				List<CodeSet> csList = ab.getConcept()
						.getDictionaryCodingConcept().getCodeSet();
				if ("create".equals(type)) {
					csList.add(codeset);
				} else if ("update".equals(type)) {
					for (int i = 0; i < csList.size(); i++) {
						if (csList.get(i).getId().equals(codeset.getId())) {
							csList.set(i, codeset);
							break;
						}
					}
				} else if ("delete".equals(type)) {
					for (int i = 0; i < csList.size(); i++) {
						if (csList.get(i).getId().equals(codeset.getId())) {
							csList.remove(i);
							break;
						}
					}
				} else {
					log.error("无法判断刷新方式：" + type + "！");
				}
			}

			ab.setCodeSets(null);
			ab.setCodeSetTrees(null);
		} catch (Exception e) {
			log.error("刷新代码集出现错误(flushCodeSet)！");
		}
	}
}
